//////////////////////////////////////////////////////////////////////////
#pragma once


namespace Math
{
	//**********************************************************************
	//	Ballistics implementations.
	//**********************************************************************

	template< typename T > inline
	const T Ballistics< T >::SolveTFromVyG( const T vy, const T g )
	{
		return vy / g;
	}

	template< typename T > inline
	const T Ballistics< T >::SolveTFromVxR( const T vx, const T r )
	{
		return r / vx;
	}

	template< typename T > inline
	const T Ballistics< T >::SolveT2FromVyG( const T vy, const T g )
	{
		return T(2) * ( vy / g );
	}

	template< typename T > inline
	const T Ballistics< T >::SolveRFromVAG( const T v, const T a, const T g )
	{
		return ((v*v) * sin( T(2)*a )) / g;
	}

	template< typename T > inline
	const T Ballistics< T >::SolvePFromVyG( const T vy, const T g )
	{
		return (vy*vy) / (T(2)*g);
	}

	template< typename T > inline
	const T Ballistics< T >::SolveVFromRAG( const T r, const T a, const T g )
	{
		return sqrt( (r*g) / sin( T(2)*a ) );
	}

	template< typename T > inline
	const T Ballistics< T >::SolveXFromVxCt( const T vx, const T Ct )
	{
		return vx*Ct;
	}

	template< typename T > inline
	const T Ballistics< T >::SolveYFromVyCtG( const T vy, const T Ct, const T g )
	{
		return vy * Ct - ( T(0.5) * g * (Ct*Ct) );
	}

	template< typename T > inline
	void Ballistics< T >::SolveAFromVRG( const T v, const T r, const T g, T& a0, T& a1 )
	{
		const T	a	=	asin( (r*g) / (v*v) );
		a0	=	a;
		a1	=	Constants< T >::HalfPi - a;
	}

	template< typename T > inline
	const bool Ballistics< T >::SolveAFromVRGTy( const T v, const T r, const T g, const T y, T& a0, T& a1 )
	{
		const T		v2		=	v*v;
		const T		v4		=	v2*v2;
		const T		r2		=	r*r;
		const T		partial	=	v4 - ( g * ( g*r2 + 2*y*v2 ) );

		// If the partial is negative, there is not enough velocity to get to target.
		if( partial <= T(0) )
			return false;

		const T		root	=	sqrt( partial );
		const T		pos		=	( v2+root ) / (g*r);
		const T		neg		=	( v2-root ) / (g*r);

		a0	=	atan( pos );
		a1	=	atan( neg );
		return true;
	}


	template< typename T > inline
	void Ballistics< T >::SolveAVFromVRGTy( const T v, const T vStep, const T r, const T g, const T y, T& outV, T& a0, T& a1 )
	{
		outV	=	v;
		while( !SolveAFromVRGTy( outV, r, g, y, a0, a1 ) )
		{
			outV	+=	vStep;
		};
	}


	//**********************************************************************
	//	Rifleman's rule implementations.
	//**********************************************************************

	template< typename T > inline
	const T Ballistics< T >::SolveRhFromRsA( const T rs, const T a )
	{
		return rs * cos( a );
	}

	template< typename T > inline
	const T Ballistics< T >::SolveAFromRhRs( const T rh, const T rs )
	{
		return cos( rh / rs );
	}
}
